package com.tc.quartz.support.service.impl;

import com.tc.quartz.frame.base.BaseService;
import com.tc.quartz.frame.base.IBaseDao;
import com.tc.quartz.frame.common.DateUtil;
import com.tc.quartz.frame.common.StringUtils;
import com.tc.quartz.support.bean.JobManagerBean;
import com.tc.quartz.support.dao.JobManagerDao;
import com.tc.quartz.support.quartz.JobClassFactory;
import com.tc.quartz.support.quartz.VpalSchedulerFactory;
import com.tc.quartz.support.service.IJobManagerService;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.MapUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * desc：任务管理
 * @author yongjin.ye
 */
@Service
public class JobManagerServiceImpl extends BaseService implements IJobManagerService {

	@Autowired
	private JobManagerDao qrtzJobManagerDao;
	
	@Resource(name="quartzDataSourceProperties")
	private Map<String, String> quartzDataSourceProperties;
	
	@Override
	public IBaseDao getBaseDao() {
		return this.qrtzJobManagerDao;
	}

	@SuppressWarnings("unchecked")
	@Override
	public void addJob(JobManagerBean jobBean) throws Exception {
		log.info(" addJob 增加任务开始 ... " + jobBean.toJson());
		String schedulerName = jobBean.getDtlSchedName();//"schedulerName-Cap-1";
		String jobName = jobBean.getDtlJobName();//"job-name-1";
		String jobGroup = jobBean.getDtlJobGroup();//Scheduler.DEFAULT_GROUP;
		String jobclassName = jobBean.getDtlJobClassName();//"com.vip.vpal.quartz.server.job.TestJob";
		String jobDescription = jobBean.getDtlDescription();//"定时任务描述";
		String triggerCron = jobBean.getCronCronExpression();//"1,31 * * * * ? ";  //"*/30 * * * * ?";
		String triggerSuffix = "_trigger";
		Date trigStartTime = StringUtils.isBlank(jobBean.getTrigStartTimeStr()) ? new Date() : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").parse(jobBean.getTrigStartTimeStr());
		Date trigEndTime = StringUtils.isBlank(jobBean.getTrigEndTimeStr()) ? null : new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").parse(jobBean.getTrigEndTimeStr());

		JobDataMap jobdata = new JobDataMap();
		String[] arrayJobData = StringUtils.nvl(jobBean.getJobDataStr(), "").split("\n");
		for (int i = 0; i < arrayJobData.length; i++) {
			if(arrayJobData[i].trim().startsWith("#")) continue;
			String[] datakv = arrayJobData[i].split("\\=");
			if("".equals(StringUtils.toTrim(datakv[0]))) continue;
			jobdata.put(StringUtils.toTrim(datakv[0]), StringUtils.toTrim(datakv.length >= 2 ? datakv[1] : null));
		}
		
		JobDataMap triggerJobdata = new JobDataMap();
		String[] arrayTriggerJobData = StringUtils.nvl(jobBean.getTriggerJobDataStr(), "").split("\n");
		for (int i = 0; i < arrayTriggerJobData.length; i++) {
			if(arrayTriggerJobData[i].trim().startsWith("#")) continue;
			String[] datakv = arrayTriggerJobData[i].split("\\=");
			if("".equals(StringUtils.toTrim(datakv[0]))) continue;
			triggerJobdata.put(StringUtils.toTrim(datakv[0]), StringUtils.toTrim(datakv.length >= 2 ? datakv[1] : null));
		}
		
		Scheduler scheduler = null;
		try {
			scheduler = VpalSchedulerFactory.getVpalScheduler(schedulerName, this.quartzDataSourceProperties);
			Class<? extends Job> clazz = JobClassFactory.getClassByName(jobclassName);
			JobDetail jobDetail = JobBuilder.newJob(clazz).withDescription(jobDescription).withIdentity(jobName, jobGroup).usingJobData(jobdata).build();

			CronTrigger trigger = (CronTrigger) TriggerBuilder.newTrigger().startAt(trigStartTime).endAt(trigEndTime)
					.withDescription(jobDescription + triggerSuffix).usingJobData(triggerJobdata)
					.withIdentity(jobName + triggerSuffix, jobGroup).withSchedule(CronScheduleBuilder.cronSchedule(triggerCron).withMisfireHandlingInstructionDoNothing()).build();

			scheduler.scheduleJob(jobDetail, trigger);
		} catch (Exception e) {
			log.error("addJob 增加任务异常", e);
			throw e;
		} finally {
			VpalSchedulerFactory.shutdown(scheduler);
		}
		log.info(" addJob 增加任务结束 ");
	}

	@Override
	public void delJob(JobManagerBean jobBean) throws Exception {
		log.info(" delJob 删除任务开始 ... " + jobBean.toJson());
		String schedulerName = jobBean.getDtlSchedName();//"schedulerName-Cap-1";
		String jobName = jobBean.getDtlJobName();//"job-name-1";
		String jobGroup = jobBean.getDtlJobGroup();//Scheduler.DEFAULT_GROUP;

		Scheduler scheduler = null;
		try {
			scheduler = VpalSchedulerFactory.getVpalScheduler(schedulerName, this.quartzDataSourceProperties);
			JobKey jobKey = new JobKey(jobName, jobGroup);
			boolean deleteResult = scheduler.deleteJob(jobKey);
			log.info("JOB删除结果：" + deleteResult);
		} catch (Exception e) {
			log.error("delJob 删除任务异常", e);
			throw e;
		} finally {
			VpalSchedulerFactory.shutdown(scheduler);
		}
		log.info(" delJob 删除任务结束 ");
	}

	@Override
	public void pauseJob(JobManagerBean jobBean) throws Exception {
		log.info(" pauseJob 暂停任务开始 ... " + jobBean.toJson());
		String schedulerName = jobBean.getDtlSchedName();//"schedulerName-Cap-1";
		String jobName = jobBean.getDtlJobName();//"job-name-1";
		String jobGroup = jobBean.getDtlJobGroup();//Scheduler.DEFAULT_GROUP;

		Scheduler scheduler = null;
		try {
			scheduler = VpalSchedulerFactory.getVpalScheduler(schedulerName, this.quartzDataSourceProperties);
			JobKey jobKey = new JobKey(jobName, jobGroup);
			scheduler.pauseJob(jobKey);
		} catch (Exception e) {
			log.error("pauseJob 暂停任务异常", e);
			throw e;
		} finally {
			VpalSchedulerFactory.shutdown(scheduler);
		}
		log.info(" pauseJob 暂停任务结束 ");
	}

	@Override
	public void resumeJob(JobManagerBean jobBean) throws Exception {
		log.info(" resumeJob 恢复任务开始 ... " + jobBean.toJson());
		String schedulerName = jobBean.getDtlSchedName();//"schedulerName-Cap-1";
		String jobName = jobBean.getDtlJobName();//"job-name-1";
		String jobGroup = jobBean.getDtlJobGroup();//Scheduler.DEFAULT_GROUP;

		Scheduler scheduler = null;
		try {
			scheduler = VpalSchedulerFactory.getVpalScheduler(schedulerName, this.quartzDataSourceProperties);
			JobKey jobKey = new JobKey(jobName, jobGroup);
			scheduler.resumeJob(jobKey);
		} catch (Exception e) {
			log.error("resumeJob 恢复任务异常", e);
			throw e;
		} finally {
			VpalSchedulerFactory.shutdown(scheduler);
		}
		log.info(" resumeJob 恢复任务结束 ");
	}

	@Override
	public void triggerJob(JobManagerBean jobBean) throws Exception {
		log.info(" triggerJob 触发任务开始 ... " + jobBean.toJson());
		String schedulerName = jobBean.getDtlSchedName();//"schedulerName-Cap-1";
		String jobName = jobBean.getDtlJobName();//"job-name-1";
		String jobGroup = jobBean.getDtlJobGroup();//Scheduler.DEFAULT_GROUP;

		JobDataMap triggerJobdata = new JobDataMap();
		String[] arrayTriggerJobData = jobBean.getTriggerJobDataStr().split("\n");
		for (int i = 0; i < arrayTriggerJobData.length; i++) {
			if(arrayTriggerJobData[i].startsWith("#")) continue;
			String[] datakv = arrayTriggerJobData[i].split("\\=");
			if("".equals(StringUtils.toTrim(datakv[0]))) continue;
			triggerJobdata.put(StringUtils.toTrim(datakv[0]), StringUtils.toTrim(datakv.length >= 2 ? datakv[1] : null));
		}
		
		Scheduler scheduler = null;
		try {
			//Class<? extends Job> clazz = JobClassFactory.getClassByName(jobBean.getDtlJobClassName());
			scheduler = VpalSchedulerFactory.getVpalScheduler(schedulerName, this.quartzDataSourceProperties);
			JobKey jobKey = new JobKey(jobName, jobGroup);
			scheduler.triggerJob(jobKey, triggerJobdata);
		} catch (Exception e) {
			log.error("triggerJob 触发任务异常", e);
			throw e;
		} finally {
			VpalSchedulerFactory.shutdown(scheduler);
		}
		log.info(" triggerJob 触发任务结束 ");
	}

	@Override
	public void updateJob(JobManagerBean jobBean) throws Exception {
		log.info(" updateJob 更新任务开始 ... " + jobBean.toJson());
		
		String[] idKey = jobBean.getId().split("\\|");
		//'id': jobJson.dtlSchedName + "|" + jobJson.dtlJobGroup + "|" + jobJson.dtlJobName
		JobManagerBean oldJobBean = new JobManagerBean();
		BeanUtils.copyProperties(oldJobBean, jobBean);
		oldJobBean.setDtlSchedName(idKey[0]);
		oldJobBean.setDtlJobGroup(idKey[1]);
		oldJobBean.setDtlJobName(idKey[2]);
		//第一步删除、第二步新增
		this.delJob(oldJobBean);
		this.addJob(jobBean);
		
		log.info(" updateJob 更新任务结束 ");
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public <T> List<T> selectSchedulerState() {
		log.info("查询节点状态开始");
		long offset = 15 * 1000;//状态检测偏移量
		List<Map> list = this.qrtzJobManagerDao.selectSchedulerState();
		for (int i = 0; i < list.size(); i++) {
			Map map = list.get(i);
			long LAST_CHECKIN_TIME = MapUtils.getLongValue(map, "LAST_CHECKIN_TIME");//最后检查时间
			long CHECKIN_INTERVAL = MapUtils.getLongValue(map, "CHECKIN_INTERVAL");//检测间隔
			
			long currInterval = System.currentTimeMillis() - LAST_CHECKIN_TIME - (CHECKIN_INTERVAL + offset); //当前偏移量后间隔
			String STATUS = currInterval > 0 ? "离线" : "在线";
			String REMARK = String.format("%s分钟", (System.currentTimeMillis() - LAST_CHECKIN_TIME) / 1000 / 60);
			
			map.put("LAST_CHECKIN_TIME_DESC", DateUtil.formatDate(LAST_CHECKIN_TIME, "yyyy-MM-dd HH:mm:ss:SSS"));
			map.put("STATUS", STATUS);
			map.put("REMARK", currInterval > 0 ? REMARK : "");
		}
		log.info("查询节点状态结束 ");
		//此处为了省事，直接使用map
		return (List<T>) list;
	}

	@SuppressWarnings({ "unchecked", "rawtypes" })
	@Override
	public <T> List<T> selectFiredTriggers() {
		log.info("查询已触发任务执行状态开始");
		List<Map> list = this.qrtzJobManagerDao.selectFiredTriggers();
		for (int i = 0; i < list.size(); i++) {
			Map map = list.get(i);
			long FIRED_TIME = MapUtils.getLongValue(map, "FIRED_TIME");
			long SCHED_TIME = MapUtils.getLongValue(map, "SCHED_TIME");
			map.put("FIRED_TIME_FORMAT", DateUtil.formatDate(FIRED_TIME, "yyyy-MM-dd HH:mm:ss:SSS"));
			map.put("SCHED_TIME_FORMAT", DateUtil.formatDate(SCHED_TIME, "yyyy-MM-dd HH:mm:ss:SSS"));
		}
		log.info("查询已触发任务执行状态结束");
		//此处为了省事，直接使用map
		return (List<T>) list;
	}
	
}
